package com.yonyou.pmclouds.task.service.rmiimpl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.billstatus.BillStatusConst;
import com.yonyou.pmclouds.basecom.bp.template.MultiInsertBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleInsertBpTemplate;
import com.yonyou.pmclouds.basecom.bp.template.SingleUpdateBpTemplate;
import com.yonyou.pmclouds.basecom.entity.KeyCountVO;
import com.yonyou.pmclouds.basecom.entity.SuperVO;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.basecom.util.BeanHelper;
import com.yonyou.pmclouds.basecom.util.CommonFieldConst;
import com.yonyou.pmclouds.im.util.IMExecutor;
import com.yonyou.pmclouds.inspectitem.mapper.InspectItemMapper;
import com.yonyou.pmclouds.picture.rmiitf.PictureRemoteService;
import com.yonyou.pmclouds.project.rmiitf.ProjectSimpleQuery;
import com.yonyou.pmclouds.task.entity.TaskConst;
import com.yonyou.pmclouds.task.entity.TaskParamVO;
import com.yonyou.pmclouds.task.entity.TaskVO;
import com.yonyou.pmclouds.task.mapper.TaskMapper;
import com.yonyou.pmclouds.task.processor.TaskBeforeInsertProcessor;
import com.yonyou.pmclouds.task.processor.TaskIMPushProcessor;
import com.yonyou.pmclouds.task.rmiitf.TaskQueryRemoteService;
import com.yonyou.pmclouds.task.rmiitf.TaskRemoteService;
import com.yonyou.pmclouds.workflow.entity.ApproveInfoParam;
import com.yonyou.pmclouds.workflow.entity.ProcessTaskVO;
import com.yonyou.pmclouds.workflow.util.BillFieldNameFormatCoverUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

@Service(version = ApplicationConsts.APPLICATION_VERSION, interfaceClass = TaskRemoteService.class)
public class TaskRemoteServiceImpl implements TaskRemoteService {

    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private ProjectSimpleQuery projectService;
    @Autowired
    private IMExecutor imExecutor;
    @Autowired
    private PictureRemoteService picService;
    @Autowired
    private InspectItemMapper inspectItemMapper;
    @Autowired
    private TaskBeforeInsertProcessor taskBeforeInsertProcessor;
    @Autowired
    private TaskIMPushProcessor taskIMPushProcessor;
    @Autowired
    private TaskQueryRemoteService taskQueryRemoteService;

    @Override
    public TaskVO insertTaskVO(TaskVO taskVO) throws BusinessException {
        SingleInsertBpTemplate<TaskVO> bp = new SingleInsertBpTemplate<TaskVO>(taskMapper);
        //为任务对象billDescribe字段添加单据重要描述
        bp.addBeforeProcessor(taskBeforeInsertProcessor);
        //生成待办信息
        bp.addAfterProcessor(taskIMPushProcessor);
        return bp.insert(taskVO);
    }

    @Override
    public TaskVO[] insertTaskVOs(TaskVO[] taskVOs) throws BusinessException {
        MultiInsertBpTemplate<TaskVO> bp = new MultiInsertBpTemplate<TaskVO>(taskMapper);
        bp.addBeforeProcessor(taskBeforeInsertProcessor);
        bp.addAfterProcessor(taskIMPushProcessor);
        return bp.insert(taskVOs);
    }

    @Override
    public TaskVO[] insertWithBuziVOs(SuperVO[] busiVOs, Map<String, TaskParamVO> paramMap)
            throws BusinessException {

        TaskVO[] taskVOs = new TaskVO[]{};
        // 单据主键和单据状态的对应map
        Map<String,Byte> buziStateMap = new HashMap<>();

        List<TaskVO> taskVOList = new ArrayList<>();
        for (int i = 0; i < busiVOs.length; i++) {
            taskVOs  = generateTaskWithParam(busiVOs[i], paramMap == null ? null : paramMap.get(busiVOs[i].pkFiledValue()));
            taskVOList.addAll(Arrays.asList(taskVOs));
            buziStateMap.put((String)busiVOs[i].pkFiledValue(),(Byte) BeanHelper.getProperty(busiVOs[i],
                    BillFieldNameFormatCoverUtil.getBillStatusFieldName(busiVOs[i])));
        }

        if(taskVOList.size() > 0){
            finishPreTask(taskVOList.toArray(new TaskVO[]{}),buziStateMap);
            taskVOs = insertTaskVOs(taskVOList.toArray(new TaskVO[]{}));
        }

        return taskVOs;
    }
    @Override
    public TaskVO[] insertWithBuziVO(SuperVO busiVO, TaskParamVO paramVO) throws BusinessException {
        TaskVO[] taskVOs = generateTaskWithParam(busiVO, paramVO);
        // 单据主键和单据状态的对应map
        Map<String,Byte> buziStateMap = new HashMap<>();
        if (ArrayUtils.isEmpty(taskVOs)) {
            return new TaskVO[0];
        } else {
            // 完成前置任务
            buziStateMap.put((String)busiVO.pkFiledValue(),(Byte) BeanHelper.getProperty(busiVO,
                    BillFieldNameFormatCoverUtil.getBillStatusFieldName(busiVO)));
            finishPreTask(taskVOs, buziStateMap);
            insertTaskVOs(taskVOs);
        }
        return taskVOs;
    }

    /**
     * 完成任务，更新task
     *
     * @param pkBill
     * @param pkReceiver
     * @param billstatus
     * @return
     * @throws BusinessException
     */
    @Override
    public synchronized TaskVO[] finishTask(String pkBill, String pkReceiver, byte billstatus) throws BusinessException {
        //同一个单据由于接收人不同，所以产生的代办信息也会有多条。
        TaskVO[] taskVOs;

        if (pkReceiver == null) {
            taskVOs = taskMapper.queryTaskByPkBill(pkBill);
        } else {
            taskVOs = taskMapper.queryTaskByBillAndReceiver(new String[]{pkBill}, pkReceiver,TaskConst.TASK_TODO);
        }

        if (ArrayUtils.isEmpty(taskVOs))
            return new TaskVO[0];

        SingleUpdateBpTemplate<TaskVO> bp = new SingleUpdateBpTemplate<TaskVO>(taskMapper,
                new String[]{TaskVO.TASK_STATUS, TaskVO.FINISHTIME, TaskVO.BILLSTATUS});

        // 目前一张单据对于一个接收人同时只会产生一条待办状态的Task
        for (TaskVO taskVO : taskVOs) {
            // 这里不更新已完成的任务的单据状态
            if (TaskConst.TASK_FINISH.equals(taskVO.getTask_status())) {
                continue;
            }
            taskVO.setTask_status(TaskConst.TASK_FINISH);
            taskVO.setBillstatus(billstatus);
            taskVO.setFinishtime(new Date());
            bp.update(taskVO);
        }
        return taskVOs;
    }

    @Override
    public TaskVO[] updateBillStatus(String pkBill, String pkReceiver, byte billStatus) throws BusinessException {
        TaskVO[] taskVOs;

        if (pkReceiver == null) {
            taskVOs = taskMapper.queryAllByPkBill(pkBill);
        } else {
            taskVOs = taskMapper.queryTaskByBillAndReceiver(new String[]{pkBill}, pkReceiver,null);
        }

        if (ArrayUtils.isEmpty(taskVOs))
            return new TaskVO[0];

        SingleUpdateBpTemplate<TaskVO> bp = new SingleUpdateBpTemplate<TaskVO>(taskMapper,
                new String[]{TaskVO.BILLSTATUS});

        // 目前一张单据对于一个接收人同时只会产生一条待办状态的Task
        for (TaskVO taskVO : taskVOs) {
            taskVO.setBillstatus(billStatus);
            bp.update(taskVO);
        }
        return taskVOs;
    }

    @Override
    public TaskVO[] insertTaskVOForWorkFlow(ApproveInfoParam approveInfoParam, byte billstatus, ProcessTaskVO[] processTaskVOs) throws BusinessException {
        String userId = RuntimeEnvironment.getLoginUserId();

        TaskVO[] taskVOs = taskMapper.queryTaskByPkBill(approveInfoParam.getPkBill());
        if (!ArrayUtils.isEmpty(taskVOs)){
            // 抢占或会签审批时，当前审批人待办至为完成，其中未审批的待办至为删除
            SingleUpdateBpTemplate<TaskVO> bp = new SingleUpdateBpTemplate<>(taskMapper,
                    new String[]{TaskVO.TASK_STATUS, TaskVO.FINISHTIME, TaskVO.BILLSTATUS, TaskVO.LAST_V_FLAG, CommonFieldConst.DR});

            // 原有任务置为完成
            for (TaskVO taskVO : taskVOs) {
                taskVO.setTask_status(TaskConst.TASK_FINISH);
                if (ArrayUtils.isEmpty(processTaskVOs)) {
                    taskVO.setLast_v_flag("Y");
                } else {
                    taskVO.setLast_v_flag("N");
                }

                taskVO.setBillstatus(billstatus);
                taskVO.setFinishtime(new Date());

                if(taskVO.getPk_receiver().equalsIgnoreCase(userId)){
                    taskVO.setDr((byte)0);
                }else {
                    taskVO.setDr((byte) 1);
                }
                bp.update(taskVO);
            }
        }

        // 当云审存在下级任务时，生成新的taskVO
        List<String> pkTasks = approveInfoParam.getPkTasks();
        TaskVO[] oldTasks = taskMapper.queryByPkTasks(pkTasks);
        if(ArrayUtils.isEmpty(oldTasks)){
            return new TaskVO[0];
        }
        if (ArrayUtils.isNotEmpty(processTaskVOs)) {
            TaskVO[] newTaskVOs = new TaskVO[processTaskVOs.length];
            for (int i = 0; i < processTaskVOs.length; i++) {
                TaskVO taskVO = new TaskVO();
                taskVO.setTaskcreator(oldTasks[0].getTaskcreator());
                taskVO.setPk_project(oldTasks[0].getPk_project());
                taskVO.setSrc_bill_type(oldTasks[0].getSrc_bill_type());
                taskVO.setTask_status(TaskConst.TASK_TODO);
                taskVO.setPk_sender(RuntimeEnvironment.getLoginUserId());
                taskVO.setPk_receiver(processTaskVOs[i].getPkReceiver());
                taskVO.setBillstatus(billstatus);
                taskVO.setCreationtime(new Date());
                taskVO.setPk_bill(approveInfoParam.getPkBill());
                taskVO.setLast_v_flag("Y");
                newTaskVOs[i] = taskVO;
            }
            return insertTaskVOs(newTaskVOs);
        }

        return taskVOs;
    }

    private TaskVO[] generateTaskWithParam(SuperVO busiVO, TaskParamVO paramVO) throws BusinessException {
        // 判断单据是否存在接收人
        if (StringUtils.isEmpty(busiVO.taskReceiverField())) {
            TaskVO vo = generateTaskVO(busiVO, null);
            return new TaskVO[]{vo};
        }
        // 判断接收人字段是否匹配
        if (BeanHelper.getProperty(busiVO, busiVO.taskReceiverField()) == null) {
            throw new BusinessException("接收人字段不匹配，请检查！");
        }
        // 判断是否存在多个接收人
        if (BeanHelper.getProperty(busiVO, busiVO.taskReceiverField()).getClass().isArray()) {
            String[] pkReceivers = (String[]) BeanHelper.getProperty(busiVO, busiVO.taskReceiverField());
            TaskVO[] taskVOS = new TaskVO[pkReceivers.length];
            int i;
            for (i = 0; i < taskVOS.length; i++) {
                String pkReceiver = pkReceivers[i];
                taskVOS[i] = generateTaskVO(busiVO, pkReceiver);
                if (paramVO != null) {
                    buildTaskVOByParam(taskVOS[i], paramVO);
                }
            }
            return taskVOS;
        } else {
            String pkReceiver = (String) BeanHelper.getProperty(busiVO, busiVO.taskReceiverField());
            TaskVO taskVO = generateTaskVO(busiVO, pkReceiver);
            if (paramVO != null) {
                buildTaskVOByParam(taskVO, paramVO);
            }
            return new TaskVO[]{taskVO};
        }
    }

    // 更新前置任务
    private void finishPreTask(TaskVO[] currTaskVOs, Map<String,Byte> buziStateMap) throws BusinessException {

        if(ArrayUtils.isEmpty(currTaskVOs))
            return ;
        String[] pkTasks = new String[currTaskVOs.length];
        for (int i = 0 ; i< currTaskVOs.length;i++){
            pkTasks[i] = currTaskVOs[i].getPk_bill();
        }

        // 查找前置任务
        TaskVO[] preTaskVOs = queryPreTaskVOs(pkTasks, currTaskVOs[0].getPk_sender());

        if(ArrayUtils.isEmpty(preTaskVOs))
            return;

        // 将发送人自己的任务设置为完成态，并为新生成的任务指定前置任务
        for(TaskVO preTaskVO : preTaskVOs){
            preTaskVO.setTask_status(TaskConst.TASK_FINISH);
            preTaskVO.setLast_v_flag("N");
            preTaskVO.setFinishtime(new Date());
            preTaskVO.setDr((byte) 1);
            preTaskVO.setBillstatus(buziStateMap.get(preTaskVO.getPk_bill()));

            update(preTaskVO, new String[]{TaskVO.TASK_STATUS, TaskVO.LAST_V_FLAG, TaskVO.BILLSTATUS, TaskVO.FINISHTIME});

            for (TaskVO taskVO : currTaskVOs){
                if(taskVO.getPk_bill().equals(preTaskVO.getPk_bill())){
                    taskVO.setPk_pretask(preTaskVO.getPk_task());
                }
            }
        }

    }

    private TaskVO update(TaskVO taskVO, String[] updateFields) throws BusinessException {
        SingleUpdateBpTemplate<TaskVO> bp = new SingleUpdateBpTemplate<TaskVO>(taskMapper, updateFields);
        return bp.update(taskVO);
    }

    /**
     * 生成待办VO
     *
     * @param vo
     * @return
     */
    private TaskVO generateTaskVO(SuperVO vo, String pkReceiver) {

        TaskVO taskVO = new TaskVO();
        taskVO.setPk_bill(getVOStringValue(vo, vo.pkFiledName()));
        // 支持驼峰命名
        taskVO.setPk_project(getVOStringValue(vo, BillFieldNameFormatCoverUtil.getPkProjectFieldName(vo)));
        taskVO.setPk_receiver(pkReceiver);
        taskVO.setPk_sender(getVOStringValue(vo, vo.taskSenderField()));
        taskVO.setTaskcreator(getVOStringValue(vo, CommonFieldConst.CREATOR));
        taskVO.setCreationtime(new Date());
        // 支持驼峰命名
        taskVO.setSrc_bill_type(getVOStringValue(vo, BillFieldNameFormatCoverUtil.getBillTypeFieldName(vo)));
        taskVO.setTask_status(TaskConst.TASK_TODO);
        taskVO.setBillstatus((byte) BeanHelper.getProperty(vo, BillFieldNameFormatCoverUtil.getBillStatusFieldName(vo)));
        taskVO.setLast_v_flag("Y");

        return taskVO;
    }

    /**
     * 方法功能描述：获取对象VO中的String类型的属性。
     *
     * <b>参数说明</b>
     *
     * @return
     * @author zhangwce
     * @time 2017年11月24日 下午12:39:52
     */
    private String getVOStringValue(SuperVO superVO, String fieldName) {
        Object obj = BeanHelper.getProperty(superVO, fieldName);
        if (obj == null)
            return null;
        return (String) obj;
    }

    /**
     * 方法功能描述：查询前置任务。
     *
     * <b>参数说明</b>
     *
     * @param pk_bills
     * @return
     * @throws BusinessException
     * @author zhangwce
     * @time 2017年11月14日 下午3:54:14
     */
    private TaskVO[] queryPreTaskVOs(String[] pk_bills, String curr_sender) throws BusinessException {

        // 单据主键、当前处理人相同的未完成的待办任务视为前置任务
        TaskVO[] taskVOs = taskQueryRemoteService.queryTaskByBillAndReceiver(pk_bills, curr_sender);
        if (ArrayUtils.isEmpty(taskVOs)) {
            return new TaskVO[0];
        }
        return taskVOs;
    }

    /**
     * 方法功能描述：将paramVO中的字段设置到taskVO中。
     *
     * <b>参数说明</b>
     *
     * @param taskVO
     * @param paramVO
     * @author zhangwce
     * @time 2017年11月24日 下午1:20:50
     */
    private void buildTaskVOByParam(TaskVO taskVO, TaskParamVO paramVO) {
        String pk_sender = paramVO.getPk_sender();
        if (pk_sender != null && !"".equals(pk_sender)) {
            taskVO.setPk_sender(pk_sender);
        }
        String pk_receiver = paramVO.getPk_receiver();
        if (pk_receiver != null && !"".contentEquals(pk_receiver)) {
            taskVO.setPk_receiver(pk_receiver);
        }
        String task_status = paramVO.getTask_status();
        if (task_status != null && !"".contentEquals(pk_receiver)) {
            taskVO.setTask_status(task_status);
        }
    }

    @Override
    public int queryBillCountByProjects(String[] projects, String[] excludeBillType, Date timeStart, Date timeEnd) {
        return taskMapper.countBillCountExcludeType(projects, excludeBillType, timeStart, timeEnd);
    }

    @Override
    public KeyCountVO[] queryProjectBillCount(String[] projects, String[] excludeBillType, Date timeStart, Date timeEnd, int start, int offset) {
        return taskMapper.countProjectBillCountExcludeType(projects, excludeBillType, timeStart, timeEnd, start, offset);
    }

    @Override
    public TaskVO[] queryByPkBill(String pkBill, String pkReceiver) {
        TaskVO[] taskVOs;
        if (pkReceiver == null) {
            taskVOs = taskMapper.queryTaskByPkBill(pkBill);
        } else {
            taskVOs = taskMapper.queryTaskByBillAndReceiver(new String[]{pkBill}, pkReceiver,TaskConst.TASK_TODO);
        }

        return taskVOs;
    }

    @Override
    public TaskVO[] updateTaskStatus(List<String> pkTasks) throws BusinessException {
        TaskVO[] taskVOS = taskMapper.queryByPkTasks(pkTasks);
        if(taskVOS != null && taskVOS.length > 0){
            SingleUpdateBpTemplate<TaskVO> bp = new SingleUpdateBpTemplate<TaskVO>(taskMapper,
                    new String[]{TaskVO.TASK_STATUS, TaskVO.FINISHTIME, TaskVO.BILLSTATUS});
            for (TaskVO taskVO : taskVOS) {
                taskVO.setTask_status(TaskConst.TASK_TODO);
                taskVO.setBillstatus(BillStatusConst.COMMON_APPROVING_STATUS);
                taskVO.setFinishtime(null);
                bp.update(taskVO);
            }
        }

        return taskVOS;
    }
}
